#include "stdafx.h"

#include "thermal_reservoir_simulator.h"
#include "thermal_main_loop_calc.h"
#include "boundary_building.h"

#include BS_FORCE_PLUGIN_IMPORT ()
#include "reservoir.h"
#include "keyword_manager.h"
#include "facility_manager.h"
#include BS_STOP_PLUGIN_IMPORT ()

namespace blue_sky
{ 
	/**
	* \brief  'default' ctor for calc_model
	* \param  param additional params for calc_model
	* */
	template <class strategy_t>
	thermal_reservoir_simulator<strategy_t>::thermal_reservoir_simulator(bs_type_ctor_param param)
		: reservoir_simulator<strategy_t>(param)
	{	  
		cm = sp_calc_model_t(BS_KERNEL.create_object (thermal_calc_model_t::bs_type ()));
		jacobian_ = sp_jacobian_t(BS_KERNEL.create_object (thermal_jacobian_t::bs_type ()));
		reservoir_ = sp_thermal_reservoir_t(BS_KERNEL.create_object (thermal_reservoir_t::bs_type ()));
	}

	/**
	* \brief  copy-ctor for calc_model
	* \param  src calc_model instance
	* */
	template <class strategy_t>
	thermal_reservoir_simulator<strategy_t>::thermal_reservoir_simulator(const blue_sky::thermal_reservoir_simulator<strategy_t> & src)
		: bs_refcounter(src), reservoir_simulator<strategy_t>(src)
	{
		if (&src != this)
			*this = src;
	}

	template <class strategy_t>
	thermal_reservoir_simulator<strategy_t>::~thermal_reservoir_simulator()
	{
	}

	template <typename strategy_t>
	typename thermal_reservoir_simulator <strategy_t>::main_loop_calc_t *
	thermal_reservoir_simulator <strategy_t>::get_main_loop (){		
		if (cm->n_phases == 3)
			return new thermal_main_loop_calc <strategy_t, true, true, true> (this);
		else if (cm->is_water () && cm->is_oil ())
			return new thermal_main_loop_calc <strategy_t, true, false, true> (this);
		else if (cm->is_gas () && cm->is_oil ())
			return new thermal_main_loop_calc <strategy_t, false, true, true> (this);
		else if (cm->is_water ())
			return new thermal_main_loop_calc <strategy_t, true, false, false> (this);
		else if (cm->is_gas ())
			return new thermal_main_loop_calc <strategy_t, false, true, false> (this);
		else if (cm->is_oil ())
			return new thermal_main_loop_calc <strategy_t, false, false, true> (this);
		else
			bs_throw_exception ("Unknown phase model");
	}

	template <typename strategy_t>
	void
	thermal_reservoir_simulator <strategy_t>::check_data (const smart_ptr <rs_mesh_iface <strategy_t>, true> &mesh, const smart_ptr <idata, true> &data)
	{
		base_t::check_data(mesh,data);
		check5 (check_temperature <strategy_t>,data, mesh, "Temperature check... ", false);
	}

	template <typename strategy_t>
	void
	thermal_reservoir_simulator <strategy_t>::init ()
	{
		
		base_t::init();
		sp_smesh_iface_t struct_msh (mesh, bs_dynamic_cast());
		index_point3d_t dimens = struct_msh->get_dimens();
		boundary_builder = BS_KERNEL.create_object(build_boundary<strategy_t>::bs_type());
		boundary_builder->set_matrix(jacobian_->get_jmatrix()->geom_matrix, mesh->get_n_active_elements (), dimens);
		
		sp_thermal_calc_model_t thermal_cm = sp_thermal_calc_model_t(cm, bs_dynamic_cast());
		thermal_cm->set_boundary_builder(boundary_builder);
	}

	template <class strategy_t>
	void 
	check_temperature (const smart_ptr <rs_mesh_iface <strategy_t>, true> &mesh, const smart_ptr <idata, true> &data)
	{
		typedef typename strategy_t::index_t index_t;
		typedef typename strategy_t::item_t item_t;
		typedef typename strategy_t::index_array_t index_array_t;
		typedef typename strategy_t::item_array_t item_array_t;

		const index_array_t &original_element_num = mesh->get_int_to_ext();
		index_t nb = mesh->get_n_active_elements ();

		array_float16_t temperature    = data->get_float_non_empty_array ("TEMPERATURE");

		for (index_t i = 0; i < nb; ++i)
		{
			index_t i_m = original_element_num[i];

	        if (temperature[i_m] <= (item_t) 0)
		      {
			    bs_throw_exception (boost::format ("TEMPERATURE for node [%d] = %f is below zero")
				  % i % temperature[i_m]);
			}
		}
	}

	// create object
	BLUE_SKY_TYPE_STD_CREATE_T_DEF (thermal_reservoir_simulator, (class));
	BLUE_SKY_TYPE_STD_COPY_T_DEF (thermal_reservoir_simulator, (class));

	// array map implementation
	BLUE_SKY_TYPE_IMPL_T_EXT (1, (thermal_reservoir_simulator<base_strategy_fi>), 1, (reservoir_simulator<base_strategy_fi>), "thermal_reservoir_simulator_fi", "Thermal reservoir simulator fi", "Thermal reservoir simulator float", false);
	BLUE_SKY_TYPE_IMPL_T_EXT (1, (thermal_reservoir_simulator<base_strategy_di>), 1, (reservoir_simulator<base_strategy_di>), "thermal_reservoir_simulator_di", "Thermal reservoir simulator di", "Thermal reservoir simulator double", false);
	BLUE_SKY_TYPE_IMPL_T_EXT (1, (thermal_reservoir_simulator<base_strategy_mixi>), 1, (reservoir_simulator<base_strategy_mixi>), "thermal_reservoir_simulator_mixi", "Thermal reservoir simulator mixi", "Thermal reservoir simulator mix", false);

	bool thermal_reservoir_simulator_register_type(const blue_sky::plugin_descriptor &pd)
	{
		bool res = true;
		res &= BS_KERNEL.register_type (pd, thermal_reservoir_simulator<base_strategy_fi>::bs_type ());
		res &= BS_KERNEL.register_type (pd, thermal_reservoir_simulator<base_strategy_di>::bs_type ());
		res &= BS_KERNEL.register_type (pd, thermal_reservoir_simulator<base_strategy_mixi>::bs_type ());
		return res;
	}
}